package edu.ccut.saturn.component.loader;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import org.dom4j.Document;
import org.dom4j.Element;
import org.osgi.framework.Bundle;

import edu.ccut.saturn.component.DatabaseManager;
import edu.ccut.saturn.component.IAuthorityResourceInfo;
import edu.ccut.saturn.component.IAuthorityRoleInfo;
import edu.ccut.saturn.component.IBundleAuthorityInfo;
import edu.ccut.saturn.component.ILogger;
import edu.ccut.saturn.component.SaturnComponentException;
import edu.ccut.saturn.component.SaturnLoggerManager;
import edu.ccut.saturn.component.impl.SaturnBundleAuthorityInfo;
import edu.ccut.saturn.component.impl.SaturnResourceInfo;
import edu.ccut.saturn.component.impl.SaturnRoleInfo;
import edu.ccut.saturn.component.xml.Dom4jUtils;

/**
 * 权限配置文件的加载类。
 * 
 * @author 温建
 * 
 * @version 1.0 2008.9.03
 * 
 * @see IBundleAuthorityInfo
 * @see IAuthorityResourceInfo
 * @see IAuthorityRoleInfo
 * 
 */
public class AuthorityLoader {

	private static final String LOGGER_KEY_LOAD_BUNDLE = SaturnLoggerManager.LOGGER_KEY_LOAD_BUNDLE;

	protected static ILogger logger = SaturnLoggerManager.getInstance()
			.getSaturnLogger(LOGGER_KEY_LOAD_BUNDLE);

	private static final String KEY_AUTHORITY_RESOURCES = "resources";

	private static final String KEY_AUTHORITY_RESOURCE = "resource";

	private static final String KEY_RESOURCE_ID = "id";

	private static final String KEY_RESOURCE_NAME = "name";

	private static final String KEY_RESOURCE_VALUE = "value";

	private static final String KEY_RESOURCE_DESCRIPTION = "description";

	private static final String KEY_AUTHORITY_ROLES = "roles";

	private static final String KEY_AUTHORITY_ROLE = "role";

	private static final String KEY_ROLE_ID = "id";

	private static final String KEY_ROLE_NAME = "name";

	private static final String KEY_ROLE_DESCRIPTION = "description";

	private static final String KEY_ROLE_RESOURCE = "resource";

	private static final String KEY_ROLE_RESOURCE_ID = "id";

	/**
	 * 加载权限配置文件,其中jsp资源的id前面需要添加“/”+bundle名的前缀；action资源的id需要加“/”+bundle名+“::”的前缀。
	 * 角色id需要添加bundle名+“::”的前缀作为唯一标识。
	 * 
	 * @param bundle
	 * @param url
	 * @return
	 * @throws SaturnComponentException
	 */
	public static IBundleAuthorityInfo loadAuthorityInfo(Bundle bundle, URL url)
			throws SaturnComponentException {

		InputStream in = null;

		try {
			logger.debug("AUTHORITY CONFIG START: \"" + bundle.getSymbolicName()
					+ "\"");

			in = url.openStream();
			return loadAuthorityInfo(bundle, in);

		} catch (IOException e) {
			logger.error(
					"Found IOException! load authority config file failed in bundle [key="
							+ bundle.getSymbolicName() + "]", e);

			throw new SaturnComponentException(
					"load authority config file failed in bundle [key="
							+ bundle.getSymbolicName() + "]", e);

		} catch (Exception e) {
			throw new SaturnComponentException(
					"load authority config file failed in bundle [key="
							+ bundle.getSymbolicName() + "]", e);

		} finally {

			try {
				if (in != null) {
					in.close();
				}

			} catch (IOException e) {
				logger.error("authority config file input stream close error!",
						e);
			}
			logger.debug("AUTHORITY CONFIG END");
			logger.debug("");
		}
	}

	@SuppressWarnings("unchecked")
	public static IBundleAuthorityInfo loadAuthorityInfo(Bundle bundle,
			InputStream in) throws SaturnComponentException {

		Document document = Dom4jUtils.getDocment(in);
		Element root = document.getRootElement();
		String symbolicname = bundle.getSymbolicName();
		Element resourcesElement = root.element(KEY_AUTHORITY_RESOURCES);

		if (resourcesElement != null) {
			List<Element> resources = resourcesElement
					.elements(KEY_AUTHORITY_RESOURCE);

			List<IAuthorityResourceInfo> authorityResourceInfos = new ArrayList<IAuthorityResourceInfo>(
					resources.size());

			for (Element resource : resources) {
				String id = resource.attributeValue(KEY_RESOURCE_ID).trim();
				String name = resource.attributeValue(KEY_RESOURCE_NAME).trim();
				String value = resource.attributeValue(KEY_RESOURCE_VALUE)
						.trim();

				StringBuffer valueStr = new StringBuffer();

				if (isJsp(value)) {
					valueStr.append("/");
					valueStr.append(symbolicname);
					valueStr.append(value);

				} else {
					valueStr.append("/");
					valueStr.append(symbolicname);
					valueStr.append("::");
					valueStr.append(value);
				}
				String description = resource.attributeValue(
						KEY_RESOURCE_DESCRIPTION).trim();

				SaturnResourceInfo saturnResourceInfo = new SaturnResourceInfo(
						symbolicname + "::" + id, name, valueStr.toString(),
						description);

				authorityResourceInfos.add(saturnResourceInfo);
			}
			List<Element> roles = root.element(KEY_AUTHORITY_ROLES).elements(
					KEY_AUTHORITY_ROLE);

			List<IAuthorityRoleInfo> authorityRoleInfo = new ArrayList<IAuthorityRoleInfo>(
					roles.size());

			for (Element role : roles) {
				String id = role.attributeValue(KEY_ROLE_ID).trim();
				String name = role.attributeValue(KEY_ROLE_NAME).trim();
				String description = role.attributeValue(KEY_ROLE_DESCRIPTION)
						.trim();

				List<Element> resourcesUnderRole = role
						.elements(KEY_ROLE_RESOURCE);

				List<IAuthorityResourceInfo> resourceInfosUnderRole = new ArrayList<IAuthorityResourceInfo>(
						resourcesUnderRole.size());

				for (Element resource : resourcesUnderRole) {
					String resourceId = resource.attributeValue(
							KEY_ROLE_RESOURCE_ID).trim();

					resourceInfosUnderRole.add(getResourceInfo(
							authorityResourceInfos, symbolicname + "::"
									+ resourceId));

				}
				SaturnRoleInfo saturnRoleInfo = new SaturnRoleInfo(symbolicname
						+ "::" + id, name, description);

				saturnRoleInfo.setResourceInfos(resourceInfosUnderRole);
				authorityRoleInfo.add(saturnRoleInfo);
			}
			SaturnBundleAuthorityInfo saturnBundleAuthorityInfo = new SaturnBundleAuthorityInfo(
					symbolicname);
			
			
			//*******************ldk************************
			try{
				insertResourceToTable(authorityResourceInfos);
			}catch(Exception e){
				//throw new SaturnComponentException("insert resource error!");
			}
			//***********************************************
			
			
			saturnBundleAuthorityInfo.setResourceInfos(authorityResourceInfos);
			saturnBundleAuthorityInfo.setRoleInfos(authorityRoleInfo);
			return saturnBundleAuthorityInfo;
		}
		return null;
	}

	private static boolean isJsp(String value) {

		if (value != null && !"".equals(value)) {

			if (value.endsWith(".jsp") || value.contains(".jsp?")) {
				return true;
			}
		}
		return false;
	}

	private static IAuthorityResourceInfo getResourceInfo(
			List<IAuthorityResourceInfo> authorityResourceInfos,
			String resourceId) {

		for (IAuthorityResourceInfo authorityResourceInfo : authorityResourceInfos) {

			if (authorityResourceInfo.getResourceKey().equals(resourceId)) {
				return authorityResourceInfo;
			}
		}
		return null;
	}
	
	/**
	 * 将资源插入资源表
	 * @param authorityResourceInfos
	 * @throws Exception
	 * @author ldk
	 */
	private static void insertResourceToTable(
			List<IAuthorityResourceInfo> authorityResourceInfos)
			throws Exception {
		Connection conn = null;
		Statement stm = null;
		try {
			conn = DatabaseManager.getInstance().getConnection();
			stm = conn.createStatement();
			for (int i = 0; i < authorityResourceInfos.size(); i++) {
				IAuthorityResourceInfo authorityResourceInfo = authorityResourceInfos
						.get(i);
				String name = authorityResourceInfo.getName();
				String value = authorityResourceInfo.getValue();
				String description = authorityResourceInfo.getDescription();
				String xlh = getXlh(stm, "SATURN_SEQUENCE_RESOURCE");
				
				if (!isResourceExist(stm, value)) {
					String insertResourceSql = "insert into saturn_auth_resource(resource_serialno,name,url,descn) ";
					insertResourceSql = insertResourceSql + " values('" + xlh
							+ "'" + ",";
					insertResourceSql = insertResourceSql + "'" + name + "'"
							+ ",";
					insertResourceSql = insertResourceSql + "'" + value + "'"
							+ ",";
					insertResourceSql = insertResourceSql + "'" + description
							+ "'" + ")";
					stm.execute(insertResourceSql);
				}
			}
		} finally {
			stm.close();
			conn.close();
		}
	}

	/**
	 * 获得序列号
	 * 
	 * @param stm
	 * @param serialname
	 * @return
	 * @throws Exception
	 * @author ldk
	 */
	private static String getXlh(Statement stm, String serialname)
			throws Exception {
		String xlh = "";
		ResultSet resultSet = null;
		try {
			String sql = "select LPAD(" + serialname.toUpperCase()
					+ ".NEXTVAL,6,'0') from dual";
			resultSet = stm.executeQuery(sql);
			if (resultSet.next()) {
				xlh = resultSet.getString(1);
			}
		} finally {
			resultSet.close();
		}
		return xlh;
	}

	/**
	 * 判断资源是否存在
	 * 
	 * @param stm
	 * @param url
	 * @return
	 * @throws Exception
	 * @author ldk
	 */
	private static boolean isResourceExist(Statement stm, String url)
			throws Exception {
		boolean flag = false;
		ResultSet resultSet = null;
		try {
			String sql = "select * from saturn_auth_resource where url=" + "'"
					+ url + "'";
			resultSet = stm.executeQuery(sql);
			if (resultSet.next()) {
				flag = true;
			}
		} finally {
			resultSet.close();
		}
		return flag;
	}

}
